package com.system.oauthserver.service.imp;

import com.alibaba.fastjson.JSONObject;
import com.system.commonutils.bean.ApiResult;
import com.system.commonutils.bean.ResponseEnum;
import com.system.commonutils.bean.SecendMenu;
import com.system.commonutils.bean.Token;
import com.system.commonutils.pojo.Role;
import com.system.commonutils.pojo.UserBean;
import com.system.commonutils.utils.RedisUtil;
import com.system.oauthserver.bean.UserParams;
import com.system.oauthserver.config.ServerConfig;
import com.system.oauthserver.mapper.RoleMapper;
import com.system.oauthserver.mapper.UserMapper;
import com.system.oauthserver.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.system.oauthserver.config.AuthorizationServerConfiguration.CLIENT_ID;
import static com.system.oauthserver.config.AuthorizationServerConfiguration.CLIENT_SECRET;

@Service
public class UserServiceImp implements UserService {

    @Autowired
    UserMapper userMapper;
    @Autowired
    RoleMapper roleMapper;
    @Autowired
    private ServerConfig serverConfig;
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    private RestTemplate restTemplate;

    @Override
    public UserBean selectUserByUsername(String s) {
        UserBean userBean = userMapper.selectUserByUsername(s);
        return userBean;
    }


    @Override
    public ApiResult login(UserParams user) {
        MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
        paramMap.add("client_id", CLIENT_ID);
        paramMap.add("client_secret", CLIENT_SECRET);
        paramMap.add("username", user.getUsername());
        paramMap.add("password", user.getPassword());
        paramMap.add("grant_type", "password");
        Token token =null;
        try {
            String url = serverConfig.getUrl() + "/oauth/token";
            restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){
                @Override
                public void handleError(ClientHttpResponse response) throws IOException {
                    if(response.getRawStatusCode() != 401){
                        super.handleError(response);
                    }
                }
            });
            token = restTemplate.postForObject(url, paramMap, Token.class);
            String access_token = token.getAccess_token();
            UserBean userInfo = redisUtil.get(access_token, UserBean.class);
            if(userInfo != null){
                //登录的时候，判断该用户是否已经登录过了
                //如果redis里面已经存在该用户已经登录过了的信息
                //我这边要刷新一遍token信息，不然，它会返回上一次还未过时的token信息给你
                //不便于做单点维护
                redisUtil.del(token.getAccess_token());
                token = oauthRefreshToken(token.getRefresh_token());
            }
        }catch (RestClientException e){
            e.printStackTrace();
        }
        if(token==null){
            return ApiResult.failure("登录失败");
        }
        UserBean userBean = userMapper.selectUserByUsername(user.getUsername());
        Role role = userBean.getRoles().get(0);

        List<SecendMenu> secendMenus = roleMapper.selectMenuByRoleId(role.getRole_id());
        role.setSecendMenus(secendMenus);

        long time = TimeUnit.DAYS.toSeconds(7);
        redisUtil.set(token.getAccess_token(), JSONObject.toJSONString(userBean), time);

        return ApiResult.successWithData(token);

    }

    @Override
    public ApiResult refreshToken(String refreshToken, String accessToken) {
        Token token = oauthRefreshToken(refreshToken);
        Object o = redisUtil.get(accessToken);
        redisUtil.set(token.getAccess_token(),o);
        redisUtil.del(accessToken);
        return ApiResult.successWithData(token);
    }

    /**
     * @description oauth2客户端刷新token
     * @param refreshToken
     * @date 2019/03/05 14:27:22
     * @author Zhifeng.Zeng
     * @return
     */
    private Token oauthRefreshToken(String refreshToken) {
        MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
        paramMap.add("client_id", CLIENT_ID);
        paramMap.add("client_secret", CLIENT_SECRET);
        paramMap.add("refresh_token", refreshToken);
        paramMap.add("grant_type", "refresh_token");
        Token token = null;
        try {
            token = restTemplate.postForObject(serverConfig.getUrl() + "/oauth/token", paramMap, Token.class);
        } catch (RestClientException e) {
            try {
                //此处应该用自定义异常去返回，在这里我就不去具体实现了
                throw new Exception(ResponseEnum.REFRESH_TOKEN_INVALID.getMessage());
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
        return token;
    }

}
